<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"
    />
    <title>理解RESTful架构 | zzqhost</title>
    <meta name="description" content="天行健，君子以自强不息；地势坤，君子以厚德载物" />
    <meta property="og:type" content="website" />
    <meta property="og:title" content="理解RESTful架构 | zzqhost" />
    <meta property="og:site_name" content="理解RESTful架构 | zzqhost" />
    <meta property="og:locale" content="zh-CN" />
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:title" content="理解RESTful架构 | zzqhost" />
    <link rel="shortcut icon" href="/favicon.ico">
    
    <link rel="preload" href="/assets/css/0.styles.948dbb0a.css" as="style"><link rel="preload" href="/assets/js/app.3e01f5cb.js" as="script"><link rel="preload" href="/assets/js/1.21aaee9f.js" as="script"><link rel="preload" href="/assets/js/14.98a4de9c.js" as="script"><link rel="preload" href="/assets/js/5.352c1a43.js" as="script"><link rel="preload" href="/assets/js/7.4a8a313c.js" as="script"><link rel="preload" href="/assets/js/9.5ce2172b.js" as="script"><link rel="preload" href="/assets/js/6.8b8fad13.js" as="script"><link rel="preload" href="/assets/js/41.5db561d2.js" as="script"><link rel="preload" href="/assets/js/13.186562af.js" as="script"><link rel="preload" href="/assets/js/15.740f4afc.js" as="script"><link rel="prefetch" href="/assets/js/10.e3f309c4.js"><link rel="prefetch" href="/assets/js/11.7bef5ef0.js"><link rel="prefetch" href="/assets/js/12.cf546b2f.js"><link rel="prefetch" href="/assets/js/16.c0f3e779.js"><link rel="prefetch" href="/assets/js/17.ee3f21b3.js"><link rel="prefetch" href="/assets/js/18.2c35035c.js"><link rel="prefetch" href="/assets/js/19.e4881cfc.js"><link rel="prefetch" href="/assets/js/20.95040517.js"><link rel="prefetch" href="/assets/js/21.cdbb212e.js"><link rel="prefetch" href="/assets/js/22.7d278bc3.js"><link rel="prefetch" href="/assets/js/23.1e2b813e.js"><link rel="prefetch" href="/assets/js/24.6cc55189.js"><link rel="prefetch" href="/assets/js/25.ea35ed40.js"><link rel="prefetch" href="/assets/js/26.2b97bfde.js"><link rel="prefetch" href="/assets/js/27.d323aa74.js"><link rel="prefetch" href="/assets/js/28.30416d07.js"><link rel="prefetch" href="/assets/js/29.02b97357.js"><link rel="prefetch" href="/assets/js/30.95aedede.js"><link rel="prefetch" href="/assets/js/31.79b824fd.js"><link rel="prefetch" href="/assets/js/32.d0cd6341.js"><link rel="prefetch" href="/assets/js/33.14c3c5b9.js"><link rel="prefetch" href="/assets/js/34.ac56f38e.js"><link rel="prefetch" href="/assets/js/35.54820345.js"><link rel="prefetch" href="/assets/js/36.37013d97.js"><link rel="prefetch" href="/assets/js/37.38353206.js"><link rel="prefetch" href="/assets/js/38.36296a20.js"><link rel="prefetch" href="/assets/js/39.37df68d6.js"><link rel="prefetch" href="/assets/js/4.54d65165.js"><link rel="prefetch" href="/assets/js/40.ffbd7a88.js"><link rel="prefetch" href="/assets/js/42.d876627b.js"><link rel="prefetch" href="/assets/js/43.e5008459.js"><link rel="prefetch" href="/assets/js/44.a24dc4a2.js"><link rel="prefetch" href="/assets/js/45.f696c4e1.js"><link rel="prefetch" href="/assets/js/8.8c0e5954.js"><link rel="prefetch" href="/assets/js/vendors~search.c4563fd1.js">
    <link rel="stylesheet" href="/assets/css/0.styles.948dbb0a.css">
  </head>
  <body>
    <div id="loader-wrapper" style="display: none;opacity:0">
      <div id="loader"></div>
      <div class="loader-section section-left"></div>
      <div class="loader-section section-right"></div>
    </div>
    <div id="app" data-server-rendered="true"><div style="height:100%;" data-v-80d5f2bc><section class="el-container main-container" data-v-80d5f2bc><aside class="el-aside menu" style="width:auto;" data-v-67e96130 data-v-80d5f2bc><ul role="menubar" class="menu-wrap el-menu" style="background-color:;" data-v-67e96130><li data-v-67e96130><div class="brand-wrap" style="background-image:url(/brand.jpg);" data-v-67e96130><div class="brand" data-v-67e96130><a href="/" class="avatar waves-effect waves-circle waves-light router-link-active" data-v-67e96130><img src="/avatar.jpg" data-v-67e96130></a> <hgroup class="introduce" data-v-67e96130><div class="nickname" data-v-67e96130>zzqhost</div> <a title="zzqhost@163.com" class="mail" data-v-67e96130>zzqhost@163.com</a></hgroup></div></div></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-home" data-v-67e96130></i> <span class="item-title" data-v-67e96130>主页</span></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-biaoqian" data-v-67e96130></i> <span class="item-title" data-v-67e96130>标签分类</span></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-wenzhang" data-v-67e96130></i> <span class="item-title" data-v-67e96130>时间归档</span></li> <!----> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-aboutme" data-v-67e96130></i> <span class="item-title" data-v-67e96130>自我介绍</span></li></ul></aside> <section class="el-container container-warp" data-v-80d5f2bc><header id="topHeader" class="el-header top-header" style="height:60px;padding-left:260px;" data-v-1a942948 data-v-80d5f2bc><div class="header-warp el-row is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-12 el-col-xs-7" data-v-1a942948><div class="el-row is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-2" data-v-1a942948><button type="button" class="el-button el-button--primary is-circle" data-v-1a942948><!----><!----><span><i class="iconfont icon-caidan" data-v-1a942948></i></span></button></div></div></div> <div class="el-col el-col-20 el-col-xs-24" data-v-1a942948><div class="grid-content bg-purple-light" data-v-1a942948><div class="el-row is-justify-end is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-13 el-col-xs-24 el-col-sm-21 el-col-md-17 el-col-lg-13" data-v-1a942948><div aria-haspopup="listbox" role="combobox" aria-owns="el-autocomplete-5666" class="el-autocomplete search-input" data-v-1a942948><div class="el-input el-input--small el-input--suffix"><!----><input type="text" autocomplete="off" valueKey="value" popperClass="search-popper" placeholder="搜搜看" fetchSuggestions="function () { [native code] }" debounce="300" placement="bottom-start" popperAppendToBody="true" value="" class="el-input__inner"><!----><span class="el-input__suffix"><span class="el-input__suffix-inner"><i class="el-input__icon el-icon-search search-ico" data-v-1a942948></i><!----></span><!----></span><!----></div><div role="region" class="el-autocomplete-suggestion el-popper search-popper" style="width:;display:none;"><div class="el-scrollbar"><div class="el-autocomplete-suggestion__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default"><ul class="el-scrollbar__view el-autocomplete-suggestion__list"></ul></div><div class="el-scrollbar__bar is-horizontal"><div class="el-scrollbar__thumb" style="width:0;transform:translateX(0%);ms-transform:translateX(0%);webkit-transform:translateX(0%);"></div></div><div class="el-scrollbar__bar is-vertical"><div class="el-scrollbar__thumb" style="height:0;transform:translateY(0%);ms-transform:translateY(0%);webkit-transform:translateY(0%);"></div></div></div></div></div></div></div></div></div></div></header> <main class="el-main my-main" style="margin-left:240px;" data-v-105de776 data-v-80d5f2bc><div class="content-header index-header" data-v-60d87e45 data-v-105de776><div class="container fade-scale in" data-v-60d87e45><h1 id="conentHeader" class="title" data-v-60d87e45>理解RESTful架构</h1> <h5 class="subtitle" data-v-60d87e45>最后更新时间：2019-07-04 18:08:36</h5></div></div> <div data-v-95d4b5b2 data-v-105de776 data-v-105de776><div class="post-content el-row is-justify-center el-row--flex" data-v-95d4b5b2><div id="post-card" class="post-card post-sign el-col el-col-16 el-col-xs-24 el-col-sm-23 el-col-md-23 el-col-lg-16" data-v-95d4b5b2><div class="content__default" data-v-95d4b5b2><p>在移动互联网的大潮下，随着docker等技术的兴起，『微服务』的概念也越来越被大家接受并应用于实践，日益增多的web service逐渐统一于RESTful 架构风格，如果开发者对RESTful 架构风格不甚了解，则开发出的所谓RESTful API总会貌合神离，不够规范。</p> <h1 id="理解restful架构"><a href="#理解restful架构" aria-hidden="true" class="header-anchor">#</a> 理解RESTful架构</h1> <h2 id="前言"><a href="#前言" aria-hidden="true" class="header-anchor">#</a> 前言</h2> <ul><li>越来越多的人开始意识到，网站即软件，而且是一种新型的软件。</li> <li>这种&quot;互联网软件&quot;采用客户端/服务器模式，建立在分布式体系上，通过互联网通信，具有高延时（high latency）、高并发等特点。</li> <li>网站开发，完全可以采用软件开发的模式。</li> <li>但是传统上，软件和网络是两个不同的领域，很少有交集；软件开发主要针对单机环境，网络则主要研究系统之间的通信。</li> <li>互联网的兴起，使得这两个领域开始融合，现在我们必须考虑，如何开发在互联网环境中使用的软件。</li> <li>RESTful架构，就是目前最流行的一种<strong>互联网软件架构</strong>。它结构清晰、符合标准、易于理解、扩展方便，所以正得到越来越多网站的采用。</li></ul> <h2 id="起源"><a href="#起源" aria-hidden="true" class="header-anchor">#</a> 起源</h2> <ul><li>REST全称是Representational State Transfer，中文意思是表述（编者注：通常译为表征）性状态转移。 我对这个词组的翻译是&quot;表现层状态转化&quot;。</li> <li>它首次出现在2000年Roy Fielding的<a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm" target="_blank" rel="noopener noreferrer">博士论文<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>中，Roy Fielding是HTTP规范的主要编写者之一。</li> <li>他在论文中提到：“我这篇文章的写作目的，就是想在符合架构原理的前提下，理解和评估以网络为基础的应用软件的架构设计，得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。”</li> <li>如果一个架构符合REST的约束条件和原则，我们就称它为RESTful架构。</li> <li>要理解RESTful架构，最好的方法就是去理解<strong>Representational State Transfer</strong>这个词组到底是什么意思，它的每一个词代表了什么涵义。如果你把这个名称搞懂了，也就不难体会REST是一种什么样的设计。</li></ul> <h2 id="初识restful"><a href="#初识restful" aria-hidden="true" class="header-anchor">#</a> 初识RESTful</h2> <p>REST本身并没有创造新的技术、组件或服务，而隐藏在RESTful背后的理念就是使用Web的现有特征和能力， 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深， 但是理论上REST架构风格并不是绑定在HTTP上，只不过目前HTTP是唯一与REST相关的实例。 所以我们这里描述的REST也是通过HTTP实现的REST.</p> <h2 id="学习restful概念"><a href="#学习restful概念" aria-hidden="true" class="header-anchor">#</a> 学习RESTful概念</h2> <ol><li><p>资源（Resources）</p> <ul><li>REST的名称&quot;表现层状态转化&quot;中，省略了主语。&quot;表现层&quot;其实指的是&quot;资源&quot;（Resources）的&quot;表现层&quot;。</li> <li>所谓&quot;资源&quot;，就是网络上的一个实体，或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务，总之就是一个具体的实在。</li> <li>你可以用一个URI（统一资源定位符）指向它，每种资源对应一个特定的URI。要获取这个资源，访问它的URI就可以，因此URI就成了每一个资源的地址或独一无二的识别符。</li> <li>所谓&quot;上网&quot;，就是与互联网上一系列的&quot;资源&quot;互动，调用它的URI。</li></ul></li> <li><p>表现层（Representation）</p> <ul><li>&quot;资源&quot;是一种信息实体，它可以有多种外在表现形式。我们把&quot;资源&quot;具体呈现出来的形式，叫做它的&quot;表现层&quot;（Representation）。</li> <li>比如，文本可以用txt格式表现，也可以用HTML格式、XML格式、JSON格式表现，甚至可以采用二进制格式；图片可以用JPG格式表现，也可以用PNG格式表现。</li> <li>URI只代表资源的实体，不代表它的形式。严格地说，有些网址最后的&quot;.html&quot;后缀名是不必要的，因为这个后缀名表示格式，属于&quot;表现层&quot;范畴，<strong>而URI应该只代表&quot;资源&quot;的位置</strong>。</li> <li>它的具体表现形式，应该在HTTP请求的头信息中用Accept和Content-Type字段指定，这两个字段才是对&quot;表现层&quot;的描述。</li></ul></li> <li><p>状态转化（State Transfer）</p> <ul><li>访问一个网站，就代表了客户端和服务器的一个互动过程。在这个过程中，势必涉及到数据和状态的变化。</li> <li>互联网通信协议HTTP协议，是一个无状态协议。这意味着，所有的状态都保存在服务器端。因此，如果客户端想要操作服务器，必须通过某种手段，让服务器端发生&quot;状态转化&quot;（State Transfer）。而这种转化是建立在表现层之上的，<strong>所以就是&quot;表现层状态转化&quot;</strong>。</li> <li>客户端用到的手段，只能是HTTP协议。具体来说，就是HTTP协议里面，四个表示操作方式的动词：<strong>GET、POST、PUT、DELETE</strong>。它们分别对应四种基本操作：GET用来获取资源，POST用来新建资源（也可以用于更新资源），PUT用来更新资源，DELETE用来删除资源。</li></ul></li></ol> <h2 id="总结"><a href="#总结" aria-hidden="true" class="header-anchor">#</a> 总结</h2> <p>综合上面的解释，我们总结一下什么是RESTful架构：</p> <ol><li>每一个URI代表一种资源；</li> <li>客户端和服务器之间，传递这种资源的某种表现层；</li> <li>客户端通过四个HTTP动词，对服务器端资源进行操作，实现&quot;表现层状态转化&quot;。</li></ol> <h2 id="误区"><a href="#误区" aria-hidden="true" class="header-anchor">#</a> 误区</h2> <p>RESTful架构有一些典型的设计误区。</p> <ol><li>最常见的一种设计错误，就是<strong>URI包含动词</strong> <ul><li>因为&quot;资源&quot;表示一种实体，所以应该是名词，URI不应该有动词，动词应该放在HTTP协议中。</li> <li>举例来说，某个URI是/posts/show/1，其中show是动词，这个URI就设计错了，正确的写法应该是/posts/1，然后用GET方法表示show。</li> <li>如果某些动作是HTTP动词表示不了的，你就应该把动作做成一种资源。
<ul><li><p>比如网上汇款，从账户1向账户2汇款500元，错误的URI是：
POST /accounts/1/transfer/500/to/2</p></li> <li><p>正确的写法是把动词transfer改成名词transaction，资源不能是动词，但是可以是一种服务：
POST /transaction HTTP/1.1
Host: 127.0.0.1</p> <pre><code>  from=1&amp;to=2&amp;amount=500.00
</code></pre></li></ul></li></ul></li> <li>另一个设计误区，就是<strong>在URI中加入版本号</strong> <ul><li>例如
　　http://www.example.com/app/1.0/foo
　　http://www.example.com/app/1.1/foo
　　http://www.example.com/app/2.0/foo</li> <li>因为不同的版本，可以理解成同一种资源的不同表现形式，所以应该采用同一个URI。版本号可以在HTTP请求头信息的Accept字段中进行区分（参见<a href="http://www.informit.com/articles/article.aspx?p=1566460" target="_blank" rel="noopener noreferrer">Versioning REST Services<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>）：
　　Accept: vnd.example-com.foo+json; version=1.0
　　Accept: vnd.example-com.foo+json; version=1.1
　　Accept: vnd.example-com.foo+json; version=2.0</li></ul></li></ol> <h2 id="参考链接"><a href="#参考链接" aria-hidden="true" class="header-anchor">#</a> 参考链接</h2> <p><a href="http://www.ruanyifeng.com/blog/2011/09/restful.html" target="_blank" rel="noopener noreferrer">阮一峰的网络日志-理解RESTful架构<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> <a href="http://www.cnblogs.com/chinajava/p/5871305.html" target="_blank" rel="noopener noreferrer">RESTful 架构风格概述<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></p></div> <span id="footerPost" data-v-95d4b5b2></span></div> <div id="post-toc" class="post-toc el-col el-col-6" data-v-95d4b5b2><h4 class="catalog-title" data-v-95d4b5b2>TOC</h4> <div class="catalog-body" data-v-95d4b5b2><ul id="catalog-list" class="catalog-list" data-v-95d4b5b2></ul></div></div></div> <div class="post-nav el-row is-justify-space-around el-row--flex" data-v-95d4b5b2><div class="post-prev el-col el-col-7" data-v-95d4b5b2><div data-v-95d4b5b2><a href="/posts/%E9%80%9A%E8%BF%87hexo%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2.html" data-v-95d4b5b2><i class="el-icon-arrow-left" data-v-95d4b5b2></i> Prev
        </a> <p class="nav-title" data-v-95d4b5b2>通过hexo搭建个人博客</p></div></div> <div class="post-next el-col el-col-7 el-col-lg-pull-5" data-v-95d4b5b2></div></div> <div class="el-row is-justify-center el-row--flex" data-v-95d4b5b2></div> <span data-v-d999c3f2 data-v-95d4b5b2><button type="button" class="el-button toc-btn el-button--primary is-circle" data-v-d999c3f2><!----><!----><span><i class="iconfont icon-service-directory" data-v-d999c3f2></i></span></button> <button type="button" class="el-button gotop-btn el-button--primary is-circle" data-v-d999c3f2><!----><!----><span><i class="el-icon-arrow-up" data-v-d999c3f2></i></span></button></span></div></main></section> <button type="button" class="el-button gotop-btn el-button--primary is-circle" style="display:none;" data-v-78a2dcfa data-v-80d5f2bc><!----><!----><span><i class="el-icon-arrow-up" data-v-78a2dcfa></i></span></button></section> <footer class="el-footer container-footer" style="height:60px;" data-v-76c50ee3 data-v-80d5f2bc><div class="footer-warp el-row is-justify-center is-align-center el-row--flex footerMargin" data-v-76c50ee3><div class="footer-top el-col el-col-24" data-v-76c50ee3><p class="ellipsis" data-v-76c50ee3><span data-v-76c50ee3>
          博客内容遵循
          <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" data-v-76c50ee3>知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span></p></div> <div class="footer-bottom el-col el-col-24" data-v-76c50ee3><p class="ellipsis" data-v-76c50ee3><span data-v-76c50ee3><span data-v-76c50ee3>
            张志强的博客 © 2017-01 ~ 2021-03
          </span></span> <span data-v-76c50ee3>
          Power by
          <a href="https://vuepress.vuejs.org/zh/" target="_blank" data-v-76c50ee3>VuePress</a> Theme
          <a href="https://github.com/zhhlwd/vuepress-theme-indigo-material" target="_blank" data-v-76c50ee3>indigo material</a></span></p></div></div></footer> <div class="overlay" data-v-80d5f2bc></div></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.3e01f5cb.js" defer></script><script src="/assets/js/1.21aaee9f.js" defer></script><script src="/assets/js/14.98a4de9c.js" defer></script><script src="/assets/js/5.352c1a43.js" defer></script><script src="/assets/js/7.4a8a313c.js" defer></script><script src="/assets/js/9.5ce2172b.js" defer></script><script src="/assets/js/6.8b8fad13.js" defer></script><script src="/assets/js/41.5db561d2.js" defer></script><script src="/assets/js/13.186562af.js" defer></script><script src="/assets/js/15.740f4afc.js" defer></script>
  </body>
</html>
